# -*- coding: utf-8 -*-
# @Time    : 2022/4/6 10:50
# @Author  : zyw
# @Email   : panda_kings@163.com
# @File    : user.py


import json
import redis

from flask import Blueprint,jsonify,Response
from werkzeug.security import generate_password_hash,check_password_hash
from captcha.image import ImageCaptcha
from common.utils.myjwt import _generate_token
from flask_restful import Api,Resource,marshal
from flask_restful import reqparse,current_app
from common.models.users import User,OauthUser
from common.models import db
from celerys.sms.smscode import sms_code
import random,string,time,base64,hmac,urllib,requests
from urllib.parse import parse_qs


# url_prefix="/user 访问路由的前缀
user_bp = Blueprint('user',__name__,url_prefix="/user")

api = Api(user_bp)


class SmsImage(Resource):
    def get(self, uuid):
        number = string.ascii_letters + string.digits
        img = "".join(random.sample(number, 4))
        print("img", img)

        img_cap = ImageCaptcha()
        img_code_data = img_cap.generate(img)
        print("img_code_data", img_code_data)

        rds = redis.Redis(host='localhost',port=6379,db=3,password=123)

        key = "image_code:%s"%uuid
        print("key",key)
        rds.set(key, img, ex=60)
        rds.close()

        return Response(img_code_data, content_type="image/png")




class Register(Resource):
    def post(self):
        """注册"""
        # TODO 注册
        parse = reqparse.RequestParser()
        parse.add_argument('username')
        parse.add_argument('password')
        parse.add_argument('sms_code')
        parse.add_argument('mobile')
        args = parse.parse_args()
        username = args.get('username')
        sms_code = args.get('sms_code')
        passwrod = args.get('password')
        mobile = args.get('mobile')

        if not all([username,passwrod,mobile]):
            return jsonify(msg='信息不完整',code=204)
        user = User.query.filter_by(account = username).first()
        if user:
            return jsonify(msg='该用户已存在',code=204)
        rds = redis.Redis(host='localhost', password=123, db=2, port=6379)
        key = '%s' % mobile
        sms = rds.get(key)
        print(sms.decode())
        print(sms_code)
        if not sms_code == sms.decode():
            return jsonify(msg='验证码不正确',code=204)
        user =User(account=username,password=passwrod,mobile=mobile)
        db.session.add(user)
        db.session.commit()
        return jsonify(msg='注册成功',code=200)


"""
1. 返回给前端的有2个token: token, refresh_token, 两个token的区别,是payload 是否携带:is_refresh
2. 客户端再次请求时要携带token refresh_token; 因为第一个token可能失效了, 此时我们要在视图函数执行前生成新token
3. 如何生成新token
    判断refresh_token中的payload的is_refresh的值是能获取到, 默认是True,是要刷新token,若获取到的是false,
    说明没有权限,要登录; 若获取到的是true 直接刷新生成新token
"""


class Login(Resource):

    def post(self):
        """登录"""
        # TODO 实现登录
        pass


# class UserInfo(Resource):
#     def get(self, uid):
#         """
#         获取用户信息
#         """
#         # try:
#         #     user = User.query.get(uid)
#         # except Exception as e:
#         #     return jsonify({'msg':"此用户不存在","code":400})
#
#         # 从缓存中查询用户信息
#         result = UserCache(uid).get()
#
#         result = json.loads(result.decode())
#         print('result>>', result)
#         # 缓存中查询到或者查询不到
#         if not result:
#             # 此时说明数据库没有这个用户
#             return jsonify({'msg':'请先注册',"code":401})
#         else:
#             data = {
#                 'name': result.get("user_name"),
#                 'gender': result.get("gender"),
#                 'photo': result.get("profile_photo")
#             }
#
#         # 对用户信息序列化返回
#         return jsonify({'msg':'用户信息获取成功',"code": data})
#
#     def patch(self):
#         """修改用户信息"""
#         # 1. 前端传来的修改后的数据
#         # 2. 写入mysql
#         # 3. 把修改后的数据写入缓存
#         pass



# 发送短信验证码

class SmsCode(Resource):
    def get(self,mobile):
        user= User.query.filter_by(mobile=mobile).first()
        if user:
            return jsonify(msg='手机号已存在',code=204,data ={'count':len(user)})
        return jsonify(msg='手机号可以注册',code=200,data = {'count':0})



class SendSmsCode(Resource):
    def post(self):
        """发送短信验证码"""
       # TODO 异步任务发送短信验证码
        pargs = reqparse.RequestParser()
        pargs.add_argument('mobile')
        args = pargs.parse_args()
        mobile = args.get('mobile')
        code = random.randint(100000, 999999)
        rds = redis.Redis(host='localhost', password=123, db=2, port=6379)
        key = '%s' % mobile
        rest = sms_code.delay(mobile, code)
        if rest:
            rds.set(key, code, 60)
            return jsonify(message='发送验证码成功', code=200, data=code)
        return jsonify(message='验证码发送失败', code=204)



class UpdatePassword(Resource):
    def post(self,uid):
        """修改密码"""
        # 获取新密码
        parse = reqparse.RequestParser()
        parse.add_argument("password")
        parse.add_argument("nickname")
        parse.add_argument("gender")
        args = parse.parse_args()
        new_pwd = args.get('password')
        new_nickname = args.get('nickname')
        new_gender = args.get('gender')

        if uid:
            user = User.query.filter_by(uid=uid).first()
        else:
            return jsonify({"msg":'获取用户信息失败',"code":400})
        # 判断当前的用户中的密码或昵称或性别是否有修改,没有修改就不修改,直接返回
        # 把旧密码覆盖掉
        # 把密码加密
        if new_pwd and check_password_hash(user.password,new_pwd):
            new_pwd_hash = generate_password_hash(new_pwd)
            User.query.filter_by(uid=uid).update({"password": new_pwd_hash})
        if (user.nick_name != new_nickname) and (new_nickname):
            User.query.filter_by(uid=uid).update({"nick_name": new_nickname})
        if (user.gender != new_gender) and (new_gender):
            User.query.filter_by(uid=uid).update({"gender": new_gender})
        else:
            return jsonify({"msg":"没有修改用户信息","code":200})
        db.session.commit()
        return jsonify({'msg':"修改成功","code":200})


class UpdateUserName(Resource):
    def post(self, name):
        """修改用户名"""
        try:
            user = User.query.filter_by(nick_name=name)
            user.update({'nick_name':name})
            db.session.commit()
            # TODO 更新缓存中的用户信息
        except Exception as e:
            return jsonify({'msg':'查找用户失败',"code":400})

class DingdingUserInfo(Resource):

    def get_ding_user(self, code):
        """获取登录的钉钉用户信息"""

        base_url = "https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature="
        # TODO 获取钉钉的配置信息
        appid = current_app.config.get('DING_APP_ID')
        appSecret = current_app.config.get('DING_REDIRECT_URI')
        t = time.time()
        # 把时间戳转换成毫秒
        timestamp = str((int(round(t*1000))))
        # 构造签名
        signature = base64.b64encode(
            hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod='sha256').digest())

        url = base_url + urllib.parse.quote(signature.decode('utf-8')) + "&timestamp="+timestamp + "&accessKey=" + appid
        print("url>>>>", url)
        resp = requests.post(url, data=json.dumps({'tmp_auth_code':code}), headers={'Content-Type': 'application/json'})
        print("ding的用户 resp>>>", resp.json())
        return resp.json().get('uid')

    def get(self):
        """根据前端传来的code, 获取钉钉登录的用户信息"""
       # TODO

        parse = reqparse.RequestParser()
        parse.add_argument('code')
        args = parse.parse_args()
        code = args.get('code')
        uid = self.get_ding_user(code)
        print('uid',uid)

        oauth = OauthUser.query.filter_by(uid=uid).first()
        if oauth:
            user = User.query.filter_by(uid = oauth.user).first()
            token,refresh_token = _generate_token(user.uid,user.account)
            return jsonify(msg="登陆成功", code=200, token=token,refresh_token=refresh_token)
        return jsonify(msg='没有绑定',code=204)


    def post(self):
        """绑定账号"""
        # TODO 实现登录的后端
        parser = reqparse.RequestParser()
        parser.add_argument('username')
        parser.add_argument('password')
        parser.add_argument('unid')
        parser.add_argument('oauth_type')
        args = parser.parse_args()
        account = args.get('account')
        pwd = args.get('password')
        unid = args.get('unid')
        oauth_type = args.get('oauth_type')

        user = OauthUser.query.filter_by(uid=unid).first()
        if user:  # 判断是否已绑定
            return jsonify(message="账号已绑定！", code=201)

        # 判断用户是否存在
        user = User.query.filter_by(account=account).first()
        if not user:
            # 此时用户不存在
            return jsonify(message="用户未注册，请先注册！", code=400)
            # 用户存在，校验密码
        rest = User.query.filter_by(password = pwd).first()
        if not rest:
            # 密码错误
            return jsonify(message="密码错误！", code=400)

        # 密码正确，进行绑定=添加数据
        user_ = OauthUser(uid=unid, user=user.uid, oauth_type=oauth_type)
        db.session.add(user_)
        db.session.commit()
        token, refresh_token = _generate_token(user.uid, user.account)
        return jsonify(msg="登陆成功", code=200, token=token,refresh_token=refresh_token)




api.add_resource(Register,'/register')
api.add_resource(Login, '/login')
# api.add_resource(UserInfo,'/userinfo/<int:uid>')
api.add_resource(SendSmsCode,"/sms_code")
api.add_resource(SmsCode,'/mobiles/<int:mobile>/count/')
api.add_resource(UpdatePassword,'/user_update/<int:uid>')
api.add_resource(UpdateUserName,'/user_update/<string:name>')
api.add_resource(SmsImage,'/image_codes/<uuid:uuid>/')
api.add_resource(DingdingUserInfo,'/dingding_login')
